#! /usr/bin/python
# -*- coding: utf-8 -*-

import ftplib
import time
import sys,os
import random
import StringIO,string
from ftplib import FTP
from optparse import OptionParser
import thread

class parseDir():
    def __init__(self, dirs):
        self.li = dirs.split('\n')[0:-1]
    def isDir(self,s):
        return s[0] == 'd'
    def getDirs(self):
        self.dirs = [string.split(w,maxsplit = 8)[-1] for w in self.li if self.isDir(w)]
        return filter(lambda x: x != '.' and x != '..',self.dirs)
    def getFiles(self):
        self.files = [(string.split(w,maxsplit = 8)[-1],string.split(w,maxsplit = 8)[4]) for w in self.li if not self.isDir(w)]
        return self.files
    
class smartFtp(object):
    def __init__(self, downloadFile):
        self.fileExt = ('.jpg','.rmvb','.rm','.wmv','.mpeg','.txt')
        self.fileDownload = downloadFile
        self.ftp = FTP()
        self.ftp.set_pasv(True)
        self.THREAD_EXIT = 0
        #self.ftp.set_debuglevel(1)
        self.startDir = os.getcwd()

    def parseCmd(self):
        usage = "usage: %prog [options] downloadFolder"
        parser = OptionParser(usage=usage)
        parser.add_option("-d","--dest",dest="pwd",
                          default="/home/",
                          help="where your download file save")
        (options, args) = parser.parse_args()
        self.fileDownload = args[0].decode('gb18030')

    def connect(self):
        sys.stdout.write('We are now trying to connect...\t\t|')
        sys.stdout.flush()
        count = 0
        while(True):
            #ftp = FTP()
            try: self.ftp.connect('202.117.54.250','4021')
            except ftplib.all_errors:
                #print e
                self.ftp.close()
                randn = random.randint(100,130)
                print '\nWe have to wait for %d seconds before reconnect...\t\t'%randn
                sys.stdout.write('                                      ')
                sys.stdout.flush()
                for i in xrange(1,randn):
                    time.sleep(1)
                    sys.stdout.write('\b\b\b')
                    sys.stdout.write("%3d"%i)
                    sys.stdout.flush()
                sys.stdout.write('\nwe can connect now...|')
                sys.stdout.flush()
                continue
            try: self.ftp.login('movie','movie')
            except ftplib.all_errors,e:
                #print e
                if count % 2 == 0:
                    sys.stdout.write('\b')
                    sys.stdout.flush()
                    sys.stdout.write('-')
                    sys.stdout.flush()
                else:
                    sys.stdout.write('\b')
                    sys.stdout.flush()
                    sys.stdout.write('|')
                    sys.stdout.flush()
                self.ftp.close()
                count+=1
                continue
            print '\nconnection build...'
            return

    def downloadThread(self,command,fp):
        self.THREAD_EXIT = 0
        fileHandler = fp.write
        try: self.ftp.retrbinary(command.encode('gb18030'), fileHandler)
        except ftplib.all_errors,e:
            print 'opps, download error:('
            print e
            fp.close()
        self.THREAD_EXIT = 1
        print '\b\b\b\b\b\b[finished]'
    def dfs(self,startFolder,startDir):
        self.ftp.cwd(startFolder.encode('gb18030'))
        if(not os.path.exists(startDir)):
            os.mkdir(startDir)
        os.chdir(startDir)
        output = StringIO.StringIO()
        sys.stdout = output
        self.ftp.dir()
        dirList = output.getvalue()
        output.close()
        sys.stdout = sys.__stdout__
        pD = parseDir(dirList.decode('gb18030'))
        for (filei, sizei) in pD.getFiles():
            print 'downloading file:',
            print filei
            pathLocal = os.path.join(startDir,filei)
            fp = open(pathLocal,'wb')
            #fileHandler = fp.write
            cmd = 'RETR '+filei
            thread.start_new_thread(self.downloadThread,(cmd,fp))
            sys.stdout.write('\t\t                              ')
            sys.stdout.flush()
            while(not self.THREAD_EXIT):
                localsize = os.path.getsize(pathLocal)
                sys.stdout.write("%5.2f%%"%(float(localsize)/long(sizei)*100))
                sys.stdout.flush()
                time.sleep(1)
                #if(localsize >= long(sizei) or localsize == 0): break
                sys.stdout.write('\b\b\b\b\b\b')
                sys.stdout.flush()
            print
                
        for diri in pD.getDirs():
            print diri
            pathServer = os.path.join(startFolder,diri)
            pathLocal  = os.path.join(startDir,diri)
            self.dfs(pathServer, pathLocal)

    def download(self):
        print 'download start...'
##        try: startDir = unicode(os.getcwd())
##        except UnicodeDecodeError:
##            startDir = os.getcwd().decode('gb18030')
        if(self.fileDownload.endswith(self.fileExt)):
            localPath = os.path.join(self.startDir,os.path.basename(fileDownload))
            fileHandler = open(localPath,'wb').write
            cmd = 'RETR '+self.fileDownload
            try: self.ftp.retrbinary(cmd.encode('gb18030'), fileHandler)
            except ftplib.all_errors:
                print "error occured when downloading..."
            print '[done]'
        else:
            startfolder = string.split(self.fileDownload,'/')[-1]
            if not startfolder:
                startfolder = string.split(self.fileDownload,'/')[-2]
            try: startDir = unicode(self.startDir)
            except: startDir = self.startDir.decode('gb18030')
            startDir = os.path.join(startDir,startfolder)
            self.dfs(self.fileDownload,startDir)
        os.chdir(self.startDir)
        self.ftp.close()
        print '\n[success~]'
    

if __name__ == '__main__':
    print '[Version 2.0 alpha]'
    print '[Bug report TO nemokingdom@gmail.com]'
    print
    while(True):
        folderDownload = raw_input("$Input the file/folder you want to download\n").decode('gb18030')
        sftp = smartFtp(folderDownload)
        sftp.connect()
        sftp.download()
    raw_input(":>")
##else:
##    parseCmd()
##    connect()
##    download()
